package cn.modfun.common.file;

import java.io.File;
import java.net.URL;
import java.net.URLDecoder;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;

public class ClassScanUtils {
	
	public static void main(String[] args) {
		/*List<Class<?>> classes = getClassesByAnnotation(Plugin.class,"com.ndasec","cn");
		for(Class cls : classes){
			System.out.println(cls.getName());
		}*/
	}

	@SuppressWarnings({ "rawtypes", "unchecked" })
	public static List<Class<?>> getClassesByAnnotation(Class annotation,String... packages){
		List<Class<?>> classes = new ArrayList<Class<?>>(),_classes = new ArrayList<Class<?>>();;
		if(packages != null){
			for(String pkg : packages){
				String pkgDir = pkg.replace('.', '/');
				Enumeration<URL> dirs;
				ClassLoader loader = Thread.currentThread().getContextClassLoader();
				try {
		            dirs = loader.getResources(pkgDir);
		            while (dirs.hasMoreElements()) {
		                URL url = dirs.nextElement();
		                String protocol = url.getProtocol();
		                String filePath = URLDecoder.decode(url.getFile(), "UTF-8");
		                if("file".equals(protocol)){
		                	File file = new File(filePath);
		                	getClassesByAnnotation(file.getAbsolutePath().substring(0,file.getAbsolutePath().length()-pkg.length()),file,classes);
		                }else if("jar".equals(protocol)){
		                	try{
		                		String path = filePath.substring("file:/".length(), filePath.indexOf('!'));
		                		JarFile jar = new JarFile(path.indexOf(':')!=-1?path:"/"+path);
		                		String _package = filePath.substring(filePath.indexOf('!')+2);
			                	Enumeration<JarEntry> entries = jar.entries();
								while (entries.hasMoreElements()) {
									JarEntry jarEntry = entries.nextElement();
									String entryName = jarEntry.getName();
									if (!jarEntry.isDirectory() && entryName.endsWith(".class") && entryName.indexOf(_package+"/") == 0) {
										String className = entryName.replace('/', '.');
										className = className.substring(0, className.length()-6);
										try {
											classes.add(Class.forName(className));
										} catch (Exception e) {
											e.printStackTrace();
										}
									}
								}
								jar.close();
		                	}catch(Exception e){
		                		e.printStackTrace();
		                	}
		                }
		            }
		        } catch (Exception e) {
		            e.getStackTrace();
		        }
			}
			if(classes!=null){
				for(Class cls : classes){
					if(cls.getAnnotation(annotation)!=null){
						_classes.add(cls);
					}
				}
			}
		}
		return _classes;
	}

	/**
	 * 通过目录获得所有类
	 */
	public static void getClassesByAnnotation(String basePath,File directory,List<Class<?>> classes){
		File flist[] = directory.listFiles();
		if (flist == null || flist.length == 0) {
			return;
		}
		for (File f : flist) {
			if (f.isDirectory()) {
				getClassesByAnnotation(basePath,f,classes);
			} else {
				if(f.getName().endsWith(".class")){
					if(f.getAbsolutePath().indexOf(basePath)==0){
						String className = f.getAbsolutePath().substring(basePath.length(),f.getAbsolutePath().length()-6).replace('\\', '.');
						try {
							classes.add(Class.forName(className));
						} catch (ClassNotFoundException e) {
							e.printStackTrace();
						}
					}
				}
			}
		}
	}
	
}
